import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * BankRecords.java
 * 
 * author: Zhiqiang Zhu
 * date: Oct/3/2020
 */

/**
 * class BankRecords
 * 
 * Read and generate customer records from CVS file.
 *
 */
public class BankRecords extends Client {
	// constants
	static private final int MAX_RECNUM = 1024;
	static private final String FILE_NAME = "bank-Detail.csv";
	static private final int OUTPUT_REC_NUM = 25;

	// array of BankRecords objects
	static BankRecords records[] = new BankRecords[MAX_RECNUM];
	static int records_count = 0;

	// array list to hold spreadsheet rows & columns
	static ArrayList<List<String>> array = new ArrayList<>();

	private String id; 			// id
	private int age; 			// age
	private String sex; 		// {FEMALE,MALE}
	private String region; 		// {INNER_CITY,TOWN,RURAL,SUBURBAN}
	private double income; 		// income
	private String married; 	// {NO,YES}
	private int children; 		// {NO,YES}
	private String car; 		// {NO,YES}
	private String save_act; 	// {NO,YES}
	private String current_act; // {NO,YES}
	private String mortgage; 	// {NO,YES}
	private String pep; 		// {YES,NO}

	// Getters and Setters
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getRegion() {
		return region;
	}

	public void setRegion(String region) {
		this.region = region;
	}

	public double getIncome() {
		return income;
	}

	public void setIncome(double income) {
		this.income = income;
	}

	public String getMarried() {
		return married;
	}

	public void setMarried(String married) {
		this.married = married;
	}

	public int getChildren() {
		return children;
	}

	public void setChildren(int children) {
		this.children = children;
	}

	public String getCar() {
		return car;
	}
	
	public void setCar(String car) {
		this.car = car;
	}

	public String getSave_act() {
		return save_act;
	}

	public void setSave_act(String save_act) {
		this.save_act = save_act;
	}

	public String getCurrent_act() {
		return current_act;
	}

	public void setCurrent_act(String current_act) {
		this.current_act = current_act;
	}

	public String getMortgage() {
		return mortgage;
	}

	public void setMortgage(String mortgage) {
		this.mortgage = mortgage;
	}

	public String getPep() {
		return pep;
	}

	public void setPep(String pep) {
		this.pep = pep;
	}

	/**
	 * readData() Load data from file into array
	 */
	@Override
	public void readData() {
		System.out.println("\nLoading data from file: " + FILE_NAME + "...");
		BufferedReader br;
		try {
			br = new BufferedReader(new FileReader(new File(FILE_NAME)));

			String line;
			while ((line = br.readLine()) != null) {
				array.add(Arrays.asList(line.split(",")));
				// System.out.println(line);
			}
		} catch (Exception e) {
			System.err.println("An error occurred while loading the file:" + e.getMessage());
		}
		
		System.out.println("Loading has been completed, records loaded: " + array.size());
		
		processData();
	}

	/**
	 * processData() Parse data from the data list and create a record object
	 */
	@Override
	public void processData() {
		int index = 0;

		System.out.println("\nProcessing data...");
		for (List<String> rowData : array) {
			// create a new record object
			records[index] = new BankRecords();

			try {
				// assign values to each field
				records[index].setId(rowData.get(0)); // get first column
				records[index].setAge(Integer.parseInt(rowData.get(1)));
				CheckSexValue(rowData.get(2));
				records[index].setSex(rowData.get(2));
				CheckRegionValue(rowData.get(3));
				records[index].setRegion(rowData.get(3));
				records[index].setIncome(Double.parseDouble(rowData.get(4)));
				CheckYesNoValue(rowData.get(5));
				records[index].setMarried(rowData.get(5));
				records[index].setChildren(Integer.parseInt(rowData.get(6)));
				CheckYesNoValue(rowData.get(7));
				records[index].setCar(rowData.get(7));
				CheckYesNoValue(rowData.get(8));
				records[index].setSave_act(rowData.get(8));
				CheckYesNoValue(rowData.get(9));
				records[index].setCurrent_act(rowData.get(9));
				CheckYesNoValue(rowData.get(10));
				records[index].setMortgage(rowData.get(10));
				CheckYesNoValue(rowData.get(11));
				records[index].setPep(rowData.get(11));
				records_count++;
			} catch (Exception e) {
				// If an exception occurs, print an error and discard this line
				System.err.println("An error occurred while parse row: " + rowData.toString());
				System.err.println(e.getMessage());
				System.err.println("This row will be skipped, continue to read the remaining data...");
				continue;
			} finally {
				index++;
			}
		}
		
		System.out.println("Data processing is completed, records generated:" + records_count);
		
		//printData();

	}

	/**
	 * printData() Print out all data records
	 */
	@Override
	public void printData() {
		if (records_count <= 0) {
			System.out.println("\nNo data to print.");
			return;
		}
		// Print header row
		System.out.println("\nThe first 25 records:");
		System.out.println("ID\t\tAGE\tSEX\tREGION\t\tINCOME\t\tMORTGAGE");
		System.out.println("--------------------------------------------------------------------------------");

		// print out
		int cnt = Math.min(records_count, OUTPUT_REC_NUM);
		for (int i = 0; i < cnt; i++) {

			String s = String.format("%s\t\t%d\t%-6s\t%-10s\t%9.2f\t%3s", // %s\t%s\t%s\t%.2f\t%s",
					records[i].getId(), records[i].getAge(), records[i].getSex(), records[i].getRegion(),
					records[i].getIncome(), records[i].getMortgage());
			System.out.println(s);
		}
		System.out.println("\nPrinting is complete.");
	}

	/**
	 * Check whether it is a valid region value If it is not legal, throw an
	 * exception
	 * 
	 * @param rv: region value
	 * @throws Exception
	 */
	private boolean CheckRegionValue(String rv) throws Exception {
		if (rv.equalsIgnoreCase("INNER_CITY") || rv.equalsIgnoreCase("TOWN") || rv.equalsIgnoreCase("RURAL")
				|| rv.equalsIgnoreCase("SUBURBAN")) {
			return true;
		} else {
			throw new Exception("Illegal value: "+ rv + ", expected value: INNER_CITY, TOWN, RURAL, SUBURBAN");
		}
	}

	/**
	 * Check whether it is a valid sex value If it is not legal, throw an
	 * exception
	 * 
	 * @param sv: sex value
	 * @throws Exception
	 */
	private boolean CheckSexValue(String sv) throws Exception {
		if (sv.equalsIgnoreCase("FEMALE") || sv.equalsIgnoreCase("MALE")) {
			return true;
		} else {
			throw new Exception("Illegal value: "+ sv + ", expected value: FEMALE, MALE");
		}
	}
	
	/**
	 * Check whether it is a valid YES/NO value If it is not legal, throw an
	 * exception
	 * 
	 * @param yv: YES/NO value
	 * @return 
	 * @throws Exception
	 */
	private boolean CheckYesNoValue(String yv) throws Exception {
		if (yv.equalsIgnoreCase("YES") || yv.equalsIgnoreCase("NO")) {
			return true;
		} else {
			throw new Exception("Illegal value: "+ yv + ", expected value: YES, NO");
		}
	}
	
	static public BankRecords[] GetRecords() {
		return records;
	}
	
	static public BankRecords[] CopyOfRecords() {
		return Arrays.copyOf(records, records_count);
	}
}
